home *** CD-ROM | disk | FTP | other *** search
/ Gigarom 1 / Gigarom Macintosh Archives (Quantum Leap)(CDRM1080320)(1993).iso / FILES / BBS / MUBBS / MUBBS etc.cpt / Module Source / Files Module / Xmodem Module Main.c < prev    next >
Text File  |  1991-11-21  |  16KB  |  508 lines

  1. /*
  2.  *  Xmodem module main.c
  3.  *
  4.  *    This program source code and it's compiled version is
  5.  *  Copyright (c) 1991 N. Hawthorn.
  6.  *  This program source code and it's compiled version IS NOT IN THE
  7.  *  PUBLIC DOMAIN ! Please read the "COPYRIGHT NOTICE / NH" file for details
  8.  *  regarding use of this program source code and it's compiled version.
  9.  *
  10.  *  This module's name is "Xmodem1", it's type is "MOD1", use a resource mover
  11.  *  to assign a new number to it, that's why we name our modules !
  12.  *
  13.  * This is where it all starts...
  14.  *
  15.  */
  16.  
  17. #define INMAIN
  18.  
  19. #include <SetUpA4.h>
  20. #include "MUBBS Module.h"
  21. #include <time.h>
  22.  
  23. struct PPP {
  24.             char filename[256]; /* the whole file and folder name */
  25.             char justname[64]; /* just the file name (for the user to see) */
  26.             long size; /* the size of a file either received or sent */
  27.             int mode; /* the mode send, receive */
  28.             int result;   /* the result of the transfer */
  29.             char reserved[32]; /* some extra bytes for future use  */
  30.             };
  31.  
  32.  
  33.  
  34. #define DOTS        60    /* SECTOR COUNTING DOTS PER LINE */
  35. #define    SECSIZ        0x80
  36. #define    BUFSIZE        0x90    /* input data buffer 128+ bytes */
  37. #define    ERRORMAX    20    /* MAX ERRORS BEFORE ABORT */
  38. #define    RETRYMAX    12    /* MAXIMUM RETRYS BEFORE ABORT */
  39. #define    RECEIVE        0    /* Receive a file */
  40. #define    SEND        1    /* Send a file */
  41.  
  42. #define    ABORT        1    /* Return ERROR */
  43. #define    NOTFOUND    2    /* Return ERROR */
  44. #define    NOCREATE    3    /* Return ERROR */
  45.  
  46. #define    SOH        1        /* START OF SECTOR CHAR */
  47. #define    EOT        4        /* end of transmission char */
  48. #define    ACK        6        /* acknowledge sector transmission */
  49. #define    NAK        21        /* error in transmission detected */
  50. #define    CAN        24        /* error in transmission detected */
  51. #define    LTRC    0x43    /* ASCII letter C */
  52.  
  53. static unsigned short Table[] = {
  54.     0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
  55.     0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
  56.     0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
  57.     0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
  58.     0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
  59.     0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
  60.     0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
  61.     0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
  62.     0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
  63.     0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
  64.     0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
  65.     0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
  66.     0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
  67.     0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
  68.     0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
  69.     0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
  70.     0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
  71.     0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
  72.     0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
  73.     0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
  74.     0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
  75.     0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  76.     0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
  77.     0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
  78.     0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
  79.     0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
  80.     0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
  81.     0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
  82.     0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
  83.     0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
  84.     0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
  85.     0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
  86. };
  87.  
  88.  
  89. pascal void main (mode1,G1,P) /* called from the main routines, and what mode to be in */
  90. int mode1;
  91. struct GS *G1; /* we point to the "global" struct in the Main Module here */
  92. Ptr P;
  93. {
  94. Handle temph;
  95. float version = 0.5; /* what version of MUBBS you are compatable with IE: .5 and above */
  96. RememberA0(); SetUpA4(); /* This sets up the A4 register to access our globals */
  97. asm { _RecoverHandle }; asm {move.l a0,temph}; HLock(temph); /* locks our module, do this ! */
  98.  
  99. G=G1; /* This MUST be the first thing you do in main only, it sets up our globals */
  100. mode[u]=mode1; /* set up our mode so that you can read it anywhere */
  101.  
  102. switch (mode[u]) { /* any un-handled modes return error from this module */
  103.     case 3:
  104.         doit(P);
  105.         G->moduleresult=0;
  106.         break;
  107.     case 98:
  108.         versionck(version); /* just return after this call, don't modify anything */
  109.         break;        
  110.     case 0:
  111.         strcpy (G->programmer,"N Hawthorn"); /* show the programmer's name up to 20 chars*/
  112.         G->moduleresult=0; /* this was also a init call if we need close call put 99 here */
  113.         break;
  114.     default:
  115.         G->moduleresult=1; /* return bad code */
  116.     };
  117.  
  118. HUnlock(temph); /* unlocks this module, do this ! */
  119. RestoreA4(); /* call this when you are all done */
  120. }
  121.  
  122.  
  123. in1() /* special Xmodem input routine that waits just 2 seconds for timeout */
  124. {
  125. int n = 0;
  126. unsigned long
  127.     secs1;
  128.     
  129. secs1=clock(); /* reset clock */
  130. loop:
  131. if (G->serin()) return(TRUE); /* no chars avail? */
  132. if ((clock() - secs1) / CLOCKS_PER_SEC < 2) goto loop;
  133. return FALSE;
  134. }
  135.  
  136.  
  137. /*
  138.     CRC Calculation
  139.  
  140.     To calculate the 16 bit CRC the message bits are considered to be the
  141.     coefficients of a polynomial. This message polynomial is first
  142.     multiplied by X^16 and then divided by the generator polynomial
  143.     (X^16 + X^12 + X^5 + 1) using modulo two arithmetic. The remainder left
  144.     after the division is the desired CRC. Since a message block in the
  145.     Modem Protocol is 128 bytes or 1024 bits, the message polynomial will
  146.     be of order X^1023. The hi order bit of the first byte of the message
  147.     block is the coefficient of X^1023 in the message polynomial. The lo
  148.     order bit of the last byte of the message block is the coefficient of
  149.     X^0 in the message polynomial.
  150.  
  151.     This function calculates the CRC used by the XMODEM/CRC Protocol.
  152.     The first argument is a pointer to the message block.
  153.     The second argument is the number of bytes in the message block.
  154.     The function returns an integer which contains the CRC.
  155. */
  156.  
  157.  
  158. unsigned int updatecrc(b, crc)
  159. unsigned char b;
  160. unsigned short crc;
  161. {
  162.     return Table[((crc >> 8) ^ b) & 0xFF] ^ (crc << 8);
  163. }
  164.  
  165. doit(P)
  166. struct PPP *P;
  167. {
  168.  
  169. if (P->mode==RECEIVE) filereceive(P);
  170. if (P->mode==SEND) filesend(P);
  171.  
  172. }
  173.  
  174.  
  175. filereceive(P)
  176. struct PPP *P;
  177. {
  178.  
  179. int
  180.     i,
  181.     first,
  182.     errors,
  183.     cancnt,
  184.     toutcnt,
  185.     errorflag,
  186.     monitortemp;
  187.  
  188.  
  189. char
  190.     condition;
  191.  
  192. unsigned char
  193.     bufr[BUFSIZE],
  194.     sectnum,
  195.     sectcurr,
  196.     sectcomp,
  197.     checksum;
  198.  
  199. unsigned int
  200.     j;
  201.  
  202. unsigned long
  203.     tempsize,
  204.     secs1;
  205.  
  206. FILE *stream;
  207.  
  208. monitortemp=G->monitor[u]; /* save the old monitor setting */
  209. G->monitor[u]=FALSE;           /* turn it off for now */
  210. G->nottransfer[u]=FALSE;  /* we are now in a transfer mode (I/O is full binary and fast) */
  211. if ((stream = fopen(P->filename, "wb")) == NULL) {
  212.     print("FILE ERROR - cannot open/create %s\n",P->filename);
  213.     P->result=NOCREATE;
  214.     goto byebye1; /* byebye1 DOESN'T try to close the file */
  215.     }
  216. else print("Xmodem Upload of \"%s\" from user\"%s\"\n",P->filename,G->username[u]);
  217.  
  218. send ("]]Ready to receive \"%s\"]",P->justname);
  219. send ("Start your Xmodem (checksum) UPLOAD (send) now]");
  220. send ("]Because this is CHECKSUM (not CRC) Xmodem, it may take a second to get going.]");
  221. send ("(Press control - X several times to cancel)...]");
  222.  
  223.  
  224. sectnum = errors = cancnt = tempsize = 0;
  225. G->serflush();
  226.  
  227. G->serout(NAK); /* send first NAK incase they're waiting*/
  228. condition=NAK; /* set the starting condition */
  229. first=1; /* first record flag for EOT */
  230. G->input[u]=0;
  231.  
  232. while(TRUE){
  233.  
  234. while ((G->input[u] != EOT) && (errors != ERRORMAX))
  235.     {
  236.     secs1 = clock(); /* Get clock ticks */
  237.     toutcnt=0;
  238.     errorflag = FALSE;
  239.     if (((sectnum) % DOTS) == 0) if (G->debuglevel > 0) print("UL<%3d>L%d ",sectnum,(u+1));
  240.  
  241.     do                    /* get sync char */
  242.         {
  243.         if ( ! G->serin()) { /* no chars avail */
  244.             if ((clock() - secs1) > 400) { /* time to send another NAK/ACK ? */
  245.                 secs1=clock(); /* reset clock */
  246.                 if (toutcnt++ > 8) {
  247.                     P->result=ABORT;
  248.                     goto byebye; /* too many NAK/ACK sent where are you ? */
  249.                     }
  250.                 G->serout(condition);
  251.                 };
  252.             }
  253.         else {
  254.             if (G->debuglevel > 1) print("\nWaiting for SOH Got char '%x'\n", G->input[u]);
  255.             if (G->input[u] == CAN) if (cancnt++ > 3) {
  256.                 P->result=ABORT;
  257.                 goto byebye;
  258.                 }
  259.             if (G->input[u] != SOH && G->input[u] != EOT) G->serflush();
  260.             }
  261.         } while ((G->input[u] != SOH) && (G->input[u] != EOT));
  262.  
  263.     if (G->input[u] == SOH) {
  264.         if (!in1()) {errorflag=TRUE; goto errout;} /* get sector count byte */
  265.         sectcurr = G->input[u];
  266.         if (!in1()) {errorflag=TRUE; goto errout;} /* get sector count byte */
  267.         sectcomp = G->input[u];
  268.         if (G->debuglevel > 1) print("Sector <$%x>, ~<$%x>, added= <$%x>", sectcurr, sectcomp,(sectcurr + sectcomp));
  269.         if (G->debuglevel > 1) print(", should be <$%x>\n", sectnum+1);
  270.         if (((sectcurr + sectcomp) & 0xFF) == 0xFF) { /* is the sector number received ok */
  271.             if (((sectnum + 1) & 0xFF) == sectcurr) { /* is it the correct sector number ? */
  272.                 checksum = 0;
  273.                 for (j = 0;j < SECSIZ;j++) { /* get the record put in file */
  274.                     if (!in1()) {errorflag=TRUE; goto errout;} /* get data byte */
  275.                     bufr[j]=G->input[u];
  276.                     checksum += G->input[u];
  277.                       /* print("\ndata <$%x>, cksm <$%x>",G->input[u] , checksum); */
  278.                     };
  279.                 if (!in1()) {errorflag=TRUE; goto errout;} /* get checksum byte */
  280.                 if (checksum == G->input[u]) { /* get the checksum byte and check it */
  281.                     for (j = 0;j < SECSIZ;j++) { /* get the record put in file */
  282.                         if ((fputc(bufr[j],stream)) == EOF) {errorflag=TRUE; goto errout;}
  283.                         };
  284.                     errors = 0;
  285.                     sectnum++;  /* move up to the next sector number */
  286.                     tempsize += SECSIZ;
  287.                     if (G->debuglevel > 1) print("Good sector. sending <ACK>\n");
  288.                     first=0; /* we got past first sector */
  289.                     G->serflush();
  290.                     condition=ACK; /* set for a time out */
  291.                     G->serout(ACK);
  292.                     }
  293.                 else {    /* its a bad checksum */
  294.                         errorflag = TRUE;
  295.                         print("checksum error, got <$%x> expected ",G->input[u]);
  296.                         print("<$%x>\n",checksum);
  297.                     };
  298.                 }
  299.             else {  /* not the correct sector number */
  300.                 if (sectcurr == sectnum) {  /* could it be the same one again ? */
  301.                     if (G->debuglevel > 0) print("\nreceived duplicate sector %d\n",sectnum);
  302.                     if (G->debuglevel > 0) print("Duplicate sector. sending <ACK>\n");
  303.                     G->serflush();
  304.                     G->serout(ACK);
  305.                     }
  306.                 else {  /* wow, we're way out of sync ! */
  307.                     if (G->debuglevel > 0 )print("Xmodem synch error\n");
  308.                     errorflag = TRUE;
  309.                     };
  310.                 };
  311.             }
  312.         else {  /* the sector number is corrupted */
  313.             if (G->debuglevel > 0) print("corrupted sector number received\n");
  314.             errorflag = TRUE;
  315.             };
  316.         };  /* "if G->input[u]==SOH" closed here */
  317.  
  318. errout:
  319.     if (errorflag == TRUE) { /* any errors ? */
  320.         errors++;
  321.         if (G->debuglevel > 0 ) {
  322.             print("C> Xmodem errors= %d\n",errors);
  323.             print("C> FILE ERROR or may be some other type of error. sending <NAK>\n");
  324.             }
  325.         wait(12); /* wait for 12 secs */
  326.         G->serflush();
  327.         condition=NAK; /* set for a time out */
  328.         G->serout(NAK);
  329.         };
  330.  
  331.     };    /* end while loop, go back and wait for another record */
  332.         
  333. if ((G->input[u] == EOT) && (errors < ERRORMAX) && (first == 0)) { /* did we get a EOT not a SOH ? */
  334.     wait(2);
  335.     G->serout(ACK);
  336.     fclose(stream);
  337.     G->monitor[u]=monitortemp; /* return the monitor to original value */
  338.     G->nottransfer[u]=TRUE;       /* back to normal mode for I/O */
  339.     P->size=tempsize;
  340.     if (G->debuglevel > 0) print("\n");
  341.     P->result=0; /* everything is OK here ! */
  342.     return; 
  343.     };
  344.  
  345. wait(12); /* wait for 12 secs */
  346. G->serflush();
  347. }; /* closes the WHILE(TRUE) loop, try again */
  348.  
  349. byebye:  /* will go here if cancel received */
  350. fclose(stream);
  351. byebye1:
  352. P->size=0;
  353. G->monitor[u]=monitortemp; /* return the monitor to original value */
  354. G->nottransfer[u]=TRUE;       /* back to normal mode for I/O */
  355. if (G->debuglevel > 0) print("\n");
  356. }
  357.  
  358.  
  359.  
  360. filesend(P)
  361. struct PPP *P;
  362. {
  363.  
  364. int
  365.     i,
  366.     endflg,
  367.     cancnt,
  368.     attempts,
  369.     crcflg,
  370.     monitortemp;
  371.  
  372. unsigned char
  373.     bufr[BUFSIZE],
  374.     sectnum,
  375.     checksum;
  376.  
  377. unsigned int
  378.     j,crc;
  379.  
  380. unsigned long
  381.     tempsize;
  382.  
  383. FILE *stream;
  384.  
  385. monitortemp=G->monitor[u]; /* save the old monitor setting */
  386. G->monitor[u]=FALSE;           /* turn it off for now */
  387. G->nottransfer[u]=FALSE;       /* we are now in a transfer mode (I/O is full binary and fast) */
  388.  
  389. if ((stream = fopen(P->filename, "rb")) == NULL) {
  390.     print("FILE ERROR - cannot open %s\n",P->filename);
  391.     P->result=NOTFOUND;
  392.     goto byebye1;
  393.     }
  394. else print("Xmodem Download \"%s\" by user \"%s\"\n",P->filename,G->username[u]);
  395.  
  396. send ("]]Ready to send \"%s\"]",P->justname);
  397. send ("Start your Xmodem DOWNLOAD (receive) now]");
  398. send ("(Press control - X several times to cancel)...]");
  399.  
  400. G->serflush();
  401. attempts = 0;
  402. sectnum = 1;
  403. j = 0;
  404.  
  405. while ((G->input[u] != NAK && G->input[u] != LTRC) && (j++ < (ERRORMAX*2))) {
  406.     if (!G->in()) {  /* get start byte */
  407.         P->result=ABORT;
  408.         goto byebye;
  409.         }
  410.     if (G->debuglevel > 1) print ("\nStart char was '%x'\n", G->input[u]);
  411.     if (G->input[u] == CAN) {
  412.         P->result=ABORT;
  413.         goto byebye;
  414.         }
  415.     if (j >= (ERRORMAX*2)) {
  416.         if (G->debuglevel > 1) print("Receiver not sending NAKs or Cs\n");
  417.         P->result=ABORT;
  418.         goto byebye;
  419.         }
  420.     }
  421.  
  422. if (G->debuglevel > 1) print ("Got start char: '%x'\n", G->input[u]);
  423. crcflg=FALSE;
  424. if (G->input[u] == LTRC) crcflg=TRUE; /* show we're in CRC mode */
  425.  
  426. G->serflush ();
  427. cancnt=0;
  428. endflg=FALSE;
  429. tempsize = 0;
  430.     
  431.     do {
  432.         attempts = 0;
  433.             for (j = 0; j < SECSIZ; j++) {
  434.                 if ((i = fgetc(stream)) == EOF) {i=0; endflg=TRUE;}
  435.                 bufr[j]=i;
  436.                 }
  437.         do {
  438.             if (((sectnum - 1) % DOTS) == 0) if (G->debuglevel > 0) print("DL<%4d>L%d ",sectnum,(u+1));
  439.             G->serout(SOH);
  440.             G->serout(sectnum);
  441.             G->serout(~sectnum);
  442.             checksum = 0;
  443.             crc = 0;
  444.             for (j = 0; j < SECSIZ; j++) {
  445.                 if (crcflg) { crc = updatecrc(bufr[j],crc); } /* for CRC */
  446.                 else checksum += bufr[j]; /* for checksum mode */
  447.                 G->serout(bufr[j]);
  448.                 }
  449.             if (crcflg) { 
  450.                  if (G->debuglevel > 1) print("ENDING CRC is <$%x>\n", crc);
  451.                 G->serout(crc >> 8); /* CRC high */
  452.                 G->serout(crc); /* CRC low */
  453.                 }
  454.             else G->serout(checksum);
  455.             tempsize += SECSIZ;
  456.             attempts++;
  457.             if (!G->in()) {
  458.                 P->result=ABORT;
  459.                 goto byebye; /* get byte */
  460.                 }
  461.             if (G->input[u] == CAN){
  462.                 if ((cancnt++) > 4) {
  463.                     P->result=ABORT;
  464.                     goto byebye;
  465.                     }
  466.                 }
  467.             if (G->debuglevel > 1) print ("Response char is '%x'\n", G->input[u]);
  468.             } while ((G->input[u] != ACK) && (attempts != RETRYMAX) && (!endflg));
  469.  
  470.         sectnum++;
  471.         } while ((attempts != RETRYMAX) && (!endflg));
  472.  
  473. fclose(stream);
  474. if (attempts == RETRYMAX)
  475.     {
  476.     if (G->debuglevel > 0) print("no acknowledgment of sector, aborting\n");
  477.     P->result=ABORT;
  478.     goto byebye;
  479.     }
  480. else
  481.     {
  482.     attempts = 0;
  483.     do {
  484.         G->serout(EOT);
  485.         if (!G->in()) { /* get sector count byte */
  486.             P->result=ABORT;
  487.             goto byebye;
  488.             }
  489.         attempts++;
  490.         } while ((G->input[u] != ACK) && (attempts != RETRYMAX));
  491.     if (attempts == RETRYMAX) if (G->debuglevel > 1) print("no acknowledgment of end of file\n");
  492.     }
  493. P->size=tempsize;
  494. G->monitor[u]=monitortemp; /* return the monitor to original value */
  495. G->nottransfer[u]=TRUE;       /* back to normal mode for I/O */
  496. if (G->debuglevel > 0) print("\n");
  497. P->result=0; /* its all OK */
  498. return;
  499.  
  500. byebye:
  501. fclose(stream);
  502. byebye1:
  503. P->size=0;
  504. G->monitor[u]=monitortemp; /* return the monitor to original value */
  505. G->nottransfer[u]=TRUE;       /* back to normal mode for I/O */
  506. if (G->debuglevel > 0) print("\n");
  507. }
  508.